package org.apache.felix.main;

import java.io.BufferedReader;
import com.quickfile.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import org.apache.felix.framework.util.Util;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;

public class Main {
	public static final String BUNDLE_DIR_SWITCH = "-b";
	public static final String SHUTDOWN_HOOK_PROP = "felix.shutdown.hook";
	public static final String SYSTEM_PROPERTIES_PROP = "felix.system.properties";
	public static final String SYSTEM_PROPERTIES_FILE_VALUE = "system.properties";
	public static final String CONFIG_PROPERTIES_PROP = "felix.config.properties";
	public static final String CONFIG_PROPERTIES_FILE_VALUE = "config.properties";
	public static final String CONFIG_DIRECTORY = "conf";
	private static Framework m_fwk = null;

	public static void main(String[] args) throws Exception {
		String bundleDir = null;
		String cacheDir = null;
		boolean expectBundleDir = false;
		for (int i = 0; i < args.length; i++) {
			if (args[i].equals("-b")) {
				expectBundleDir = true;
			} else if (expectBundleDir) {
				bundleDir = args[i];
				expectBundleDir = false;
			} else {
				cacheDir = args[i];
			}
		}

		if ((args.length > 3) || ((expectBundleDir) && (bundleDir == null))) {
			System.out
					.println("Usage: [-b <bundle-deploy-dir>] [<bundle-cache-dir>]");
			System.exit(0);
		}

		loadSystemProperties();

		Properties configProps = loadConfigProperties();

		if (configProps == null) {
			System.err.println("No config.properties found.");
			configProps = new Properties();
		}

		copySystemProperties(configProps);

		if (bundleDir != null) {
			configProps.setProperty("felix.auto.deploy.dir", bundleDir);
		}

		if (cacheDir != null) {
			configProps.setProperty("org.osgi.framework.storage", cacheDir);
		}

		String enableHook = configProps.getProperty("felix.shutdown.hook");
		if ((enableHook == null) || (!enableHook.equalsIgnoreCase("false"))) {
			Runtime.getRuntime().addShutdownHook(
					new Thread("Felix Shutdown Hook") {
						public void run() {
							try {
								if (Main.m_fwk != null) {
									Main.m_fwk.stop();
									Main.m_fwk.waitForStop(0L);
								}
							} catch (Exception ex) {
								System.err.println("Error stopping framework: "
										+ ex);
							}
						}
					});
		}

		try {
			FrameworkFactory factory = getFrameworkFactory();
			m_fwk = factory.newFramework((Map) configProps);

			m_fwk.init();

			AutoProcessor.process(configProps, m_fwk.getBundleContext());
			FrameworkEvent event;
			do {
				m_fwk.start();

				event = m_fwk.waitForStop(0L);
			}

			while (event.getType() == 128);

			System.exit(0);
		} catch (Exception ex) {
			System.err.println("Could not create framework: " + ex);
			ex.printStackTrace();
			System.exit(0);
		}
	}

	private static FrameworkFactory getFrameworkFactory() throws Exception {
		URL url = Main.class.getClassLoader().getResource(
				"META-INF/services/org.osgi.framework.launch.FrameworkFactory");

		if (url != null) {
			BufferedReader br = new BufferedReader(new InputStreamReader(
					url.openStream()));
			try {
				for (String s = br.readLine(); s != null; s = br.readLine()) {
					s = s.trim();

					if ((s.length() <= 0) || (s.charAt(0) == '#'))
						continue;
					FrameworkFactory localFrameworkFactory = (FrameworkFactory) Class
							.forName(s).newInstance();
					return localFrameworkFactory;
				}
			} finally {
				if (br != null)
					br.close();
			}
		}

		throw new Exception("Could not find framework factory.");
	}

	public static void loadSystemProperties() {
		URL propURL = null;
		String custom = System.getProperty("felix.system.properties");
		if (custom != null) {
			try {
				propURL = new URL(custom);
			} catch (MalformedURLException ex) {
				System.err.print("Main: " + ex);
				return;
			}

		} else {
			File confDir = null;
			String classpath = System.getProperty("java.class.path");
			int index = classpath.toLowerCase().indexOf("felix.jar");
			int start = classpath.lastIndexOf(File.pathSeparator, index) + 1;
			if (index >= start) {
				String jarLocation = classpath.substring(start, index);

				confDir = File.newInstance(File.newInstance(
						File.newInstance(jarLocation).getAbsolutePath()).getParent(),
						"conf");
			} else {
				confDir = File.newInstance(System.getProperty("user.dir"), "conf");
			}

			try {
				propURL = File.newInstance(confDir, "system.properties").toURL();
			} catch (MalformedURLException ex) {
				System.err.print("Main: " + ex);
				return;
			}

		}

		Properties props = new Properties();
		InputStream is = null;
		try {
			is = propURL.openConnection().getInputStream();
			props.load(is);
			is.close();
		} catch (FileNotFoundException ex) {
		} catch (Exception ex) {
			System.err.println("Main: Error loading system properties from "
					+ propURL);

			System.err.println("Main: " + ex);
			try {
				if (is != null)
					is.close();
			} catch (IOException ex2) {
			}

			return;
		}

		for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
			String name = (String) e.nextElement();
			System.setProperty(name,
					Util.substVars(props.getProperty(name), name, null, null));
		}
	}

	public static Properties loadConfigProperties() {
		URL propURL = null;
		String custom = System.getProperty("felix.config.properties");
		if (custom != null) {
			try {
				propURL = new URL(custom);
			} catch (MalformedURLException ex) {
				System.err.print("Main: " + ex);
				return null;
			}

		} else {
			File confDir = null;
			String classpath = System.getProperty("java.class.path");
			int index = classpath.toLowerCase().indexOf("felix.jar");
			int start = classpath.lastIndexOf(File.pathSeparator, index) + 1;
			if (index >= start) {
				String jarLocation = classpath.substring(start, index);

				confDir = File.newInstance(File.newInstance(
						File.newInstance(jarLocation).getAbsolutePath()).getParent(),
						"conf");
			} else {
				confDir = File.newInstance(System.getProperty("user.dir"), "conf");
			}

			try {
				propURL = File.newInstance(confDir, "config.properties").toURL();
			} catch (MalformedURLException ex) {
				System.err.print("Main: " + ex);
				return null;
			}

		}

		Properties props = new Properties();
		InputStream is = null;
		try {
			is = propURL.openConnection().getInputStream();
			props.load(is);
			is.close();
		} catch (Exception ex) {
			try {
				if (is != null)
					is.close();

			} catch (IOException ex2) {
			}

			return null;
		}

		for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
			String name = (String) e.nextElement();
			props.setProperty(name,
					Util.substVars(props.getProperty(name), name, null, props));
		}

		return props;
	}

	public static void copySystemProperties(Properties configProps) {
		Enumeration e = System.getProperties().propertyNames();
		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			if ((key.startsWith("felix."))
					|| (key.startsWith("org.osgi.framework."))) {
				configProps.setProperty(key, System.getProperty(key));
			}
		}
	}
}